package com.zhentao.dataintegrity.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhentao.dataintegrity.domain.dto.IntegrityTaskDTO;
import com.zhentao.dataintegrity.domain.entity.DataTypeConfig;
import com.zhentao.dataintegrity.domain.entity.IntegrityTask;
import com.zhentao.dataintegrity.mapper.DataTypeConfigMapper;
import com.zhentao.dataintegrity.mapper.IntegrityTaskMapper;
import com.zhentao.dataintegrity.service.IntegrityExecutionService;
import com.zhentao.dataintegrity.service.IntegrityTaskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
public class IntegrityTaskServiceImpl implements IntegrityTaskService {

    private static final Logger log = LoggerFactory.getLogger(IntegrityTaskServiceImpl.class);

    @Autowired
    private IntegrityTaskMapper integrityTaskMapper;

    @Autowired
    private DataTypeConfigMapper dataTypeConfigMapper;

    @Autowired
    private IntegrityExecutionService executionService;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public IPage<IntegrityTaskDTO> getTaskPage(int pageNo, int pageSize, String taskTitle, String taskStatus, String triggerType) {
        Page<IntegrityTask> page = new Page<>(pageNo, pageSize);
        IPage<IntegrityTask> taskPage = integrityTaskMapper.selectTaskPage(page, taskTitle, taskStatus, triggerType);
        
        IPage<IntegrityTaskDTO> dtoPage = taskPage.convert(this::convertToDTO);
        return dtoPage;
    }

    @Override
    public IntegrityTaskDTO getTaskDetail(Long id) {
        IntegrityTask task = integrityTaskMapper.selectById(id);
        if (task == null) {
            return null;
        }
        return convertToDTO(task);
    }

    @Override
    @Transactional
    public Long createTask(IntegrityTaskDTO taskDTO) {
        // 检查任务标题是否存在
        if (checkTaskTitleExists(taskDTO.getTaskTitle(), null)) {
            throw new RuntimeException("任务标题已存在");
        }

        IntegrityTask task = new IntegrityTask();
        BeanUtils.copyProperties(taskDTO, task);
        
        // 转换数据类型列表为JSON
        try {
            task.setDataTypes(objectMapper.writeValueAsString(taskDTO.getDataTypes()));
        } catch (JsonProcessingException e) {
            throw new RuntimeException("数据类型序列化失败", e);
        }
        
        // 设置默认值
        task.setTaskStatus("ENABLED");
        task.setScheduleTime(taskDTO.getScheduleTime() != null ? taskDTO.getScheduleTime() : "02:00");
        
        // 生成Cron表达式
        if ("SCHEDULED".equals(taskDTO.getTriggerType())) {
            task.setScheduleCron(generateCronExpression(taskDTO.getScheduleType(), taskDTO.getScheduleTime()));
        }
        
        task.setCreatedTime(LocalDateTime.now());
        task.setUpdatedTime(LocalDateTime.now());
        
        integrityTaskMapper.insert(task);
        
        // 计算下次运行时间
        if ("SCHEDULED".equals(task.getTriggerType()) && "ENABLED".equals(task.getTaskStatus())) {
            calculateNextRunTime(task.getId());
        }
        
        return task.getId();
    }

    @Override
    @Transactional
    public boolean updateTask(IntegrityTaskDTO taskDTO) {
        // 检查任务标题是否存在
        if (checkTaskTitleExists(taskDTO.getTaskTitle(), taskDTO.getId())) {
            throw new RuntimeException("任务标题已存在");
        }

        IntegrityTask task = integrityTaskMapper.selectById(taskDTO.getId());
        if (task == null) {
            throw new RuntimeException("任务不存在");
        }

        BeanUtils.copyProperties(taskDTO, task);
        
        // 转换数据类型列表为JSON
        try {
            task.setDataTypes(objectMapper.writeValueAsString(taskDTO.getDataTypes()));
        } catch (JsonProcessingException e) {
            throw new RuntimeException("数据类型序列化失败", e);
        }
        
        // 更新Cron表达式
        if ("SCHEDULED".equals(taskDTO.getTriggerType())) {
            task.setScheduleCron(generateCronExpression(taskDTO.getScheduleType(), taskDTO.getScheduleTime()));
        }
        
        task.setUpdatedTime(LocalDateTime.now());
        
        int result = integrityTaskMapper.updateById(task);
        
        // 重新计算下次运行时间
        if ("SCHEDULED".equals(task.getTriggerType()) && "ENABLED".equals(task.getTaskStatus())) {
            calculateNextRunTime(task.getId());
        }
        
        return result > 0;
    }

    @Override
    @Transactional
    public boolean deleteTask(Long id) {
        IntegrityTask task = new IntegrityTask();
        task.setId(id);
        task.setIsDelete(1);
        task.setUpdatedTime(LocalDateTime.now());
        
        return integrityTaskMapper.updateById(task) > 0;
    }

    @Override
    @Transactional
    public boolean enableTask(Long id) {
        int result = integrityTaskMapper.updateTaskStatus(id, "ENABLED");
        if (result > 0) {
            calculateNextRunTime(id);
        }
        return result > 0;
    }

    @Override
    @Transactional
    public boolean disableTask(Long id) {
        return integrityTaskMapper.updateTaskStatus(id, "DISABLED") > 0;
    }

    @Override
    public String runTaskImmediately(Long id, LocalDate startDate, LocalDate endDate) {
        IntegrityTask task = integrityTaskMapper.selectById(id);
        if (task == null) {
            throw new RuntimeException("任务不存在");
        }
        
        IntegrityTaskDTO taskDTO = convertToDTO(task);
        return executionService.executeTask(taskDTO, "MANUAL", startDate, endDate);
    }

    @Override
    public boolean cancelExecution(String executionId) {
        return executionService.cancelExecution(executionId);
    }

    @Override
    public List<IntegrityTaskDTO.DataTypeOption> getDataTypeOptions() {
        List<DataTypeConfig> configs = dataTypeConfigMapper.selectActiveConfigs();
        return configs.stream()
                .map(config -> new IntegrityTaskDTO.DataTypeOption(config.getTypeCode(), config.getTypeName(), false))
                .collect(Collectors.toList());
    }

    @Override
    public boolean checkTaskTitleExists(String taskTitle, Long excludeId) {
        return integrityTaskMapper.checkTaskTitleExists(taskTitle, excludeId) > 0;
    }

    @Override
    public IntegrityTaskDTO getTaskStatistics() {
        IntegrityTask statistics = integrityTaskMapper.getTaskStatistics();
        IntegrityTaskDTO dto = new IntegrityTaskDTO();
        // 这里可以设置统计信息到DTO中
        return dto;
    }

    @Override
    public List<IntegrityTaskDTO> getRecentTasks(int limit) {
        List<IntegrityTask> tasks = integrityTaskMapper.selectRecentTasks(limit);
        return tasks.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void calculateNextRunTime(Long taskId) {
        IntegrityTask task = integrityTaskMapper.selectById(taskId);
        if (task == null || !"SCHEDULED".equals(task.getTriggerType()) || !"ENABLED".equals(task.getTaskStatus())) {
            return;
        }

        LocalDateTime nextRunTime = calculateNextRunTime(task.getScheduleType(), task.getScheduleTime());
        integrityTaskMapper.updateNextRunTime(taskId, nextRunTime);
    }

    @Override
    public void executeScheduledTasks() {
        List<IntegrityTask> tasks = integrityTaskMapper.selectScheduledTasks(LocalDateTime.now());
        
        for (IntegrityTask task : tasks) {
            try {
                IntegrityTaskDTO taskDTO = convertToDTO(task);
                
                // 根据时间范围类型计算数据范围
                LocalDate[] dateRange = calculateDataRange(task.getTimeRangeType());
                
                // 执行任务
                executionService.executeTask(taskDTO, "SCHEDULED", dateRange[0], dateRange[1]);
                
                // 计算下次运行时间
                calculateNextRunTime(task.getId());
                
            } catch (Exception e) {
                log.error("执行定时任务失败: taskId={}, error={}", task.getId(), e.getMessage(), e);
                
                // 更新任务状态为失败
                integrityTaskMapper.updateRunStatus(task.getId(), LocalDateTime.now(), "FAILED", 
                    e.getMessage(), BigDecimal.ZERO, BigDecimal.ZERO, 
                    calculateNextRunTime(task.getScheduleType(), task.getScheduleTime()));
            }
        }
    }

    /**
     * 转换为DTO
     */
    private IntegrityTaskDTO convertToDTO(IntegrityTask task) {
        IntegrityTaskDTO dto = new IntegrityTaskDTO();
        BeanUtils.copyProperties(task, dto);
        
        // 转换数据类型JSON为列表
        try {
            if (task.getDataTypes() != null) {
                List<String> dataTypes = objectMapper.readValue(task.getDataTypes(), new TypeReference<List<String>>() {});
                dto.setDataTypes(dataTypes);
            }
        } catch (JsonProcessingException e) {
            log.error("数据类型反序列化失败", e);
        }
        
        // 设置文本字段
        dto.setTaskStatusText(getTaskStatusText(task.getTaskStatus()));
        dto.setLastRunStatusText(getRunStatusText(task.getLastRunStatus()));
        dto.setTriggerTypeText(getTriggerTypeText(task.getTriggerType()));
        dto.setTimeRangeTypeText(getTimeRangeTypeText(task.getTimeRangeType()));
        
        return dto;
    }

    /**
     * 生成Cron表达式
     */
    private String generateCronExpression(String scheduleType, String scheduleTime) {
        String[] timeParts = scheduleTime.split(":");
        int hour = Integer.parseInt(timeParts[0]);
        int minute = timeParts.length > 1 ? Integer.parseInt(timeParts[1]) : 0;
        
        if ("MONTHLY".equals(scheduleType)) {
            return String.format("0 %d %d 1 * ?", minute, hour); // 每月1号
        } else if ("WEEKLY".equals(scheduleType)) {
            return String.format("0 %d %d ? * MON", minute, hour); // 每周一
        }
        
        return String.format("0 %d %d * * ?", minute, hour); // 每天
    }

    /**
     * 计算下次运行时间
     */
    private LocalDateTime calculateNextRunTime(String scheduleType, String scheduleTime) {
        LocalDateTime now = LocalDateTime.now();
        String[] timeParts = scheduleTime.split(":");
        int hour = Integer.parseInt(timeParts[0]);
        int minute = timeParts.length > 1 ? Integer.parseInt(timeParts[1]) : 0;
        
        LocalDateTime nextRun = now.withHour(hour).withMinute(minute).withSecond(0).withNano(0);
        
        if ("MONTHLY".equals(scheduleType)) {
            nextRun = nextRun.withDayOfMonth(1);
            if (nextRun.isBefore(now)) {
                nextRun = nextRun.plusMonths(1);
            }
        } else if ("WEEKLY".equals(scheduleType)) {
            nextRun = nextRun.with(java.time.DayOfWeek.MONDAY);
            if (nextRun.isBefore(now)) {
                nextRun = nextRun.plusWeeks(1);
            }
        } else {
            if (nextRun.isBefore(now)) {
                nextRun = nextRun.plusDays(1);
            }
        }
        
        return nextRun;
    }

    /**
     * 计算数据范围
     */
    private LocalDate[] calculateDataRange(String timeRangeType) {
        LocalDate endDate = LocalDate.now().minusDays(1); // 昨天
        LocalDate startDate;
        
        switch (timeRangeType) {
            case "MONTH_1":
                startDate = endDate.minusMonths(1);
                break;
            case "MONTH_3":
                startDate = endDate.minusMonths(3);
                break;
            case "MONTH_6":
                startDate = endDate.minusMonths(6);
                break;
            case "YEAR_1":
                startDate = endDate.minusYears(1);
                break;
            default:
                startDate = endDate.minusMonths(1);
        }
        
        return new LocalDate[]{startDate, endDate};
    }

    /**
     * 获取任务状态文本
     */
    private String getTaskStatusText(String status) {
        Map<String, String> statusMap = new HashMap<>();
        statusMap.put("ENABLED", "启用");
        statusMap.put("DISABLED", "禁用");
        return statusMap.getOrDefault(status, status);
    }

    /**
     * 获取运行状态文本
     */
    private String getRunStatusText(String status) {
        Map<String, String> statusMap = new HashMap<>();
        statusMap.put("SUCCESS", "执行完毕");
        statusMap.put("FAILED", "执行失败");
        statusMap.put("RUNNING", "运行中");
        return statusMap.getOrDefault(status, status);
    }

    /**
     * 获取触发方式文本
     */
    private String getTriggerTypeText(String type) {
        Map<String, String> typeMap = new HashMap<>();
        typeMap.put("SCHEDULED", "定时");
        typeMap.put("MANUAL", "人工");
        return typeMap.getOrDefault(type, type);
    }

    /**
     * 获取时间范围类型文本
     */
    private String getTimeRangeTypeText(String type) {
        Map<String, String> typeMap = new HashMap<>();
        typeMap.put("MONTH_1", "近1个月");
        typeMap.put("MONTH_3", "近3个月");
        typeMap.put("MONTH_6", "近半年");
        typeMap.put("YEAR_1", "近1年");
        return typeMap.getOrDefault(type, type);
    }
}
